package common

import (
	"encoding/json"
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"strconv"
	"time"

	"github.com/clbanning/mxj"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"go-papers/constant"
	"go-papers/notice"
	"go-papers/tools"

	"go-papers/common/http"
	"go-papers/middleware"
	"go-papers/models"
	"go-papers/pkg/lognew"
	"go-papers/tools/config"

	"go-papers/common/go-wechat/common"
	"go-papers/models/protocols"
	"go-papers/pkg/wechat"
	"go-papers/tools/app"
)

func GetConfig(c *gin.Context) {

	app.CommonResp(c, 0, "ok", nil)
}

func GetAccessToken(c *gin.Context) {
	res, err := wechat.Server.Token().GetToken(2000)
	if err != nil {
		app.CommonResp(c, 500, "失败"+err.Error(), "")
		return
	}
	t := string(res)
	app.CommonResp(c, 0, "ok", t)
}

func ShareUrl(c *gin.Context) {
	var data protocols.WeixinShare
	err := c.BindWith(&data, binding.JSON)
	if err != nil {
		app.ApiResp(c, -1, "数据解析失败", data)
		return
	}
	//
	res, _ := wechat.Server.User().GetShareUrl(data.UrlPath)
	app.CommonResp(c, 0, "ok", res)

}

// 邮箱：pengpeng007008@163.com
// 密码：wmzh21c301
func UpdateOpenId(c *gin.Context) {
	var data protocols.WeixinS

	err := c.BindWith(&data, binding.JSON)
	if err != nil {
		app.ApiResp(c, -1, "数据解析失败", data)
		return
	}
	// 获取用户信息
	cc := common.CGetUserBaseInfoRequest{
		OpenId: data.OpenId,
		Lang:   "",
	}
	res, err := wechat.Server.User().GetUserBaseInfo(&cc, 600)
	if err != nil {
		app.ApiResp(c, -1, "异常"+err.Error(), res)
		return
	}
	//根据用户信息存入数据库
	var cs models.ThirdUser
	cs.ThirdType = "wx"
	cs.ThridOpenId = res.Openid
	cs.ThirdActive = time.Now().Format("2006-01-02 15:04:05")
	cs.ThridAvatar = res.HeadImgUrl
	cs.ThirdAddr = res.Country + "," + res.Province + "," + res.City
	cs.ThridNickName = res.Nickname
	cs.ThirdUnionId = res.UnionId
	cs.ThirdSex = strconv.Itoa(res.Sex)
	cs.ThirdSubscribe = strconv.Itoa(res.Subscribe)
	cs.ThirdStatus = "1"
	ff, err := cs.InsertUpdate()
	if err != nil {
		app.ApiResp(c, -1, "异常"+err.Error(), ff)
		return
	}
	ff.Token = ""
	//根据 第三方id 查询是否有 关联 用户od
	var memberThird models.MemberThirdInfo
	memberThird.ThirdUserId = ff.ThridUserId
	mf, er := memberThird.Get()
	if er == nil && mf.MemberId >= 0 {
		//生产登陆token
		authGatewayMiddleware, err := middleware.AuthGatewayInit()
		if err == nil {
			ff.Token = authGatewayMiddleware.GatewayLoginHandlerToken(c, mf.MemberId)
		}
	}

	app.CommonResp(c, 0, "ok", ff)
}

// UpdateCode
func UpdateCode(c *gin.Context) {
	var data protocols.WeixinReq

	err := c.BindWith(&data, binding.JSON)
	if err != nil {
		app.ApiResp(c, -1, "数据解析失败", data)
		return
	}
	if data.Code == "" {
		app.ApiResp(c, -1, "数据解析失败", data)
		return
	}
	//根据code 获取 用户access_token + openId
	aid := config.GConfig.Wechat.AppId
	ss := config.GConfig.Wechat.AppSecret
	url := "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + aid + "&secret=" + ss + "&code=" + data.Code + "&grant_type=authorization_code"
	resp, err := http.Get(url)
	if err != nil {
		app.ApiResp(c, -1, "获取openId异常"+err.Error(), resp)
		return
	}

	//解析
	var wx protocols.WeixinOpen
	_ = json.Unmarshal([]byte(resp), &wx)

	lognew.Info(c, "UpdateCode", lognew.Fields{"data": data, "resp": resp})
	if wx.Errcode != 0 {
		rtp := make(map[string]interface{})
		rtp["resp"] = resp
		app.ApiResp(c, -1, "获取openId异常/"+wx.Errmsg, rtp)
		return
	}
	openId := wx.Openid
	if openId == "" {
		rtp := make(map[string]interface{})
		rtp["wx"] = wx
		rtp["data"] = data
		app.ApiResp(c, -1, "获取openId异常/为空", rtp)
		return
	}

	res := &common.CGetUserBaseInfoResponse{}
	if data.Scope == "snsapi_userinfo" {
		//通过当前的token 获取
		url2 := "https://api.weixin.qq.com/sns/userinfo?access_token=" + wx.AccessToken + "&openid=" + openId + "&lang=zh_CN"

		resp, err := http.Get(url2)
		if err != nil {
			app.ApiResp(c, -1, "获取用户信息异常"+err.Error(), resp)
			return
		}
		_ = json.Unmarshal([]byte(resp), res)

	} else {

		// 获取用户信息
		cc := common.CGetUserBaseInfoRequest{
			OpenId: openId,
			Lang:   "zh_CN",
		}
		res, err := wechat.Server.User().GetUserBaseInfo(&cc, 600)
		if err != nil {
			app.ApiResp(c, -1, "异常"+err.Error(), res)
			return
		}
	}

	//根据用户信息存入数据库
	var cs models.ThirdUser
	cs.ThirdType = "wx"
	cs.ThridOpenId = openId
	cs.ThirdActive = time.Now().Format("2006-01-02 15:04:05")
	cs.ThridAvatar = res.HeadImgUrl
	cs.ThirdAddr = res.Country + "," + res.Province + "," + res.City
	cs.ThridNickName = res.Nickname
	cs.ThirdUnionId = res.UnionId
	cs.ThirdStatus = "1"
	cs.ThirdSex = strconv.Itoa(res.Sex)
	cs.ThirdSubscribe = strconv.Itoa(res.Subscribe)
	ff, err := cs.InsertUpdate()
	if err != nil {
		app.ApiResp(c, -1, "异常"+err.Error(), ff)
		return
	}
	ff.Token = ""
	//根据 第三方id 查询是否有 关联 用户od
	var memberThird models.MemberThirdInfo
	memberThird.ThirdUserId = ff.ThridUserId
	mf, er := memberThird.Get()
	if er == nil && mf.MemberId >= 0 {
		//生产登陆token
		authGatewayMiddleware, err := middleware.AuthGatewayInit()
		if err == nil {
			ff.Token = authGatewayMiddleware.GatewayLoginHandlerToken(c, mf.MemberId)
		}
	}

	app.CommonResp(c, 0, "ok", ff)
}

func GetMenu(c *gin.Context) {
	res, err := wechat.Server.Menu().GetAll(300)
	if err != nil {
		app.CommonResp(c, 500, "err", err.Error())
	}
	app.CommonResp(c, 0, "ok", res)
}

func CreateMenu(c gin.Context) {
	// data
	buttons := []common.CButton{}
	button1 := common.CButton{}
	button1.Name = "下单"
	button1.Type = common.ButtonTypeClick
	button1.Key = "order"
	buttons = append(buttons, button1)
	buttonSearch := common.CButton{}
	searchButtons := []common.CButton{}
	buttonSearch.Name = "搜索"
	baiduSearch := common.CButton{}
	baiduSearch.Name = "百度一下"
	baiduSearch.Type = common.ButtonTypeView
	baiduSearch.Url = "https://www.baidu.com"
	searchButtons = append(searchButtons, baiduSearch)
	sougouSearch := common.CButton{}
	sougouSearch.Name = "搜狗搜索"
	sougouSearch.Type = common.ButtonTypeView
	sougouSearch.Url = "http://www.sogou.com"
	searchButtons = append(searchButtons, sougouSearch)
	buttonSearch.SubButton = searchButtons
	buttons = append(buttons, buttonSearch)
	button3 := common.CButton{}
	button3.Name = "扫一扫"
	button3.Type = common.ButtonTypeScancodeWaitmsg
	button3.Key = "take_photo"
	buttons = append(buttons, button3)

	err := wechat.Server.Menu().Create(&buttons, 30)
	fmt.Println("buttons menu create", err)
}

// ----
// --- 订单退款 回调
// ----
func OrderRefund(c *gin.Context) {
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		lognew.Error(c, "OrderRefundBack", lognew.Fields{"msg": "read http body failed！error msg:" + err.Error()})
		return
	}
	lognew.Info(c, "OrderRefundBack-IN", lognew.Fields{"msg": "wechat refund notify body :" + string(body)})
	var wx_notify_req common.PayNotifyResult

	err = xml.Unmarshal(body, &wx_notify_req)
	if err != nil {
		lognew.Info(c, "OrderRefundBack", lognew.Fields{"msg": "read http body xml failed! err :" + err.Error()})
		return
	}
	mv, err := mxj.NewMapXml(body)
	if err != nil {
		lognew.Info(c, "OrderRefundBack", lognew.Fields{"msg": err.Error()})
		return
	}

	backInfo, _ := mv["xml"].(map[string]interface{})

	lognew.Info(c, "OrderRefundBack-Sign", lognew.Fields{"backInfo": backInfo})

	sign, _ := backInfo["sign"].(string)
	//进行签名校验
	if wechat.Server.WechatPay().VerifySign(backInfo, sign) {

		// 生产callback log
		ck := models.OrderCallback{}

		ck.TransactionId, _ = backInfo["transaction_id"].(string)
		ck.OutTradeNo, _ = backInfo["out_trade_no"].(string)
		ck.TimeEnd, _ = backInfo["time_end"].(string)
		ck.Appid, _ = backInfo["appid"].(string)
		ck.MchId, _ = backInfo["mch_id"].(string)
		ck.SubAppid, _ = backInfo["sub_appid"].(string)
		ck.SubMchId, _ = backInfo["sub_mch_id"].(string)
		ck.DeviceInfo, _ = backInfo["device_info"].(string)
		ck.NonceStr, _ = backInfo["nonce_str"].(string)
		ck.SignType, _ = backInfo["sign_type"].(string)
		ck.Sign, _ = backInfo["sign"].(string)
		ck.ResultCode, _ = backInfo["result_code"].(string)
		ck.ErrCode, _ = backInfo["err_code"].(string)
		ck.ErrCodeDes, _ = backInfo["err_code_des"].(string)
		ck.Openid, _ = backInfo["openid"].(string)
		ck.IsSubscribe, _ = backInfo["is_subscribe"].(string)
		ck.SubOpenid, _ = backInfo["sub_openid"].(string)
		ck.TradeType, _ = backInfo["trade_type"].(string)
		ck.BankType, _ = backInfo["bank_type"].(string)

		totalFee, _ := backInfo["total_fee"].(string)
		ck.TotalFee, _ = tools.StringToInt(totalFee)

		ck.CashFee, _ = backInfo["cash_fee"].(string)
		ck.FeeType, _ = backInfo["fee_type"].(string)
		ck.CashFeeType, _ = backInfo["cash_fee_type"].(string)

		SettlementTotalFee, _ := backInfo["settlement_total_fee"].(string)
		ck.SettlementTotalFee, _ = tools.StringToInt(SettlementTotalFee)

		CouponFee, _ := backInfo["coupon_fee"].(string)
		ck.CouponFee, _ = tools.StringToInt(CouponFee)

		CouponCount, _ := backInfo["coupon_count"].(string)
		ck.CouponCount, _ = tools.StringToInt(CouponCount)

		_, err = ck.Create()
		if err != nil {
			lognew.Error(c, "OrderTradeBackInsert", lognew.Fields{"ck": ck, "err": err.Error()})
		}
		// 订单支付成功状态流转
		var trade models.OrderTrade
		tradeInfo, err := trade.GetByNO(ck.OutTradeNo)
		if err != nil {
			lognew.Error(c, "OrderTradeFind", lognew.Fields{"ck": ck, "err": err.Error()})
			c.XML(200, gin.H{
				"return_code": "FAIL",
				"return_msg":  "failed to verify sign, please retry!",
			})
			return
		}
		var order models.Order
		orderInfo, err := order.GetByID(tradeInfo.OrderId)
		if err != nil {
			lognew.Error(c, "orderFind", lognew.Fields{"ck": ck, "err": err.Error()})
			c.XML(200, gin.H{
				"return_code": "FAIL",
				"return_msg":  "failed to verify sign, please retry!",
			})
			return
		}

		orderPay := models.OrderPay{
			OrderId:  orderInfo.OrderId,
			PayType:  "微信",
			PayPrice: float64(ck.TotalFee) / 100.0,
			PayDesc:  orderInfo.OrderName,
			PayCome:  5,
			PayNo:    ck.OutTradeNo,
			PayTime:  time.Now().Format("2006-01-02 15:04:05"),
		}
		_, _ = orderPay.Create() //微信支付 回调创建 pay记录

		lognew.Info(c, "OrderRefund-SUCCESS", lognew.Fields{"backInfo": backInfo})

		//用户操作订单记录
		orlog := models.OrderOprateLog{
			OrderId:         orderInfo.OrderId,
			Title:           "订单退款成功确认",
			Desc:            "订单退款成功确认/操作人：微信服务器/退款金额：" + fmt.Sprintf("%0.2f", orderPay.PayPrice),
			LogType:         "3",
			OrderStatusName: tools.OrderStatusName(orderInfo.OrderStatus),
			PayStatusName:   tools.PayStatusName(orderInfo.PayTime, orderInfo.RefundTime),
			LogName:         "订单退款成功确认",
			LogUid:          0,
		}
		_, _ = orlog.Create() // 订单退款成功确认

		c.XML(200, gin.H{
			"return_code": "SUCCESS",
			"return_msg":  "OK",
		})
	} else {

		lognew.Info(c, "OrderRefund-FAIL", lognew.Fields{"backInfo": backInfo})

		c.XML(200, gin.H{
			"return_code": "FAIL",
			"return_msg":  "failed to verify sign, please retry!",
		})
	}
	return

}

// ----
// --- 订单支付成功 回调
// ----
func OrderBack(c *gin.Context) {
	body, err := ioutil.ReadAll(c.Request.Body)
	if err != nil {
		lognew.Error(c, "OrderBack", lognew.Fields{"msg": "read http body failed！error msg:" + err.Error()})
		return
	}

	lognew.Info(c, "OrderBack-IN", lognew.Fields{"msg": "wechat pay notify body :" + string(body)})

	var wx_notify_req common.PayNotifyResult

	err = xml.Unmarshal(body, &wx_notify_req)
	if err != nil {
		lognew.Info(c, "OrderBack", lognew.Fields{"msg": "read http body xml failed! err :" + err.Error()})
		return
	}
	mv, err := mxj.NewMapXml(body)
	if err != nil {
		lognew.Info(c, "OrderBack", lognew.Fields{"msg": err.Error()})
		return
	}

	backInfo, _ := mv["xml"].(map[string]interface{})

	lognew.Info(c, "OrderBack-Sign", lognew.Fields{"backInfo": backInfo})

	sign, _ := backInfo["sign"].(string)
	//进行签名校验
	if wechat.Server.WechatPay().VerifySign(backInfo, sign) {

		// 生产callback log
		ck := models.OrderCallback{}

		ck.TransactionId, _ = backInfo["transaction_id"].(string)
		ck.OutTradeNo, _ = backInfo["out_trade_no"].(string)
		ck.TimeEnd, _ = backInfo["time_end"].(string)
		ck.Appid, _ = backInfo["appid"].(string)
		ck.MchId, _ = backInfo["mch_id"].(string)
		ck.SubAppid, _ = backInfo["sub_appid"].(string)
		ck.SubMchId, _ = backInfo["sub_mch_id"].(string)
		ck.DeviceInfo, _ = backInfo["device_info"].(string)
		ck.NonceStr, _ = backInfo["nonce_str"].(string)
		ck.SignType, _ = backInfo["sign_type"].(string)
		ck.Sign, _ = backInfo["sign"].(string)
		ck.ResultCode, _ = backInfo["result_code"].(string)
		ck.ErrCode, _ = backInfo["err_code"].(string)
		ck.ErrCodeDes, _ = backInfo["err_code_des"].(string)
		ck.Openid, _ = backInfo["openid"].(string)
		ck.IsSubscribe, _ = backInfo["is_subscribe"].(string)
		ck.SubOpenid, _ = backInfo["sub_openid"].(string)
		ck.TradeType, _ = backInfo["trade_type"].(string)
		ck.BankType, _ = backInfo["bank_type"].(string)

		totalFee, _ := backInfo["total_fee"].(string)
		ck.TotalFee, _ = tools.StringToInt(totalFee)

		ck.CashFee, _ = backInfo["cash_fee"].(string)
		ck.FeeType, _ = backInfo["fee_type"].(string)
		ck.CashFeeType, _ = backInfo["cash_fee_type"].(string)

		SettlementTotalFee, _ := backInfo["settlement_total_fee"].(string)
		ck.SettlementTotalFee, _ = tools.StringToInt(SettlementTotalFee)

		CouponFee, _ := backInfo["coupon_fee"].(string)
		ck.CouponFee, _ = tools.StringToInt(CouponFee)

		CouponCount, _ := backInfo["coupon_count"].(string)
		ck.CouponCount, _ = tools.StringToInt(CouponCount)

		_, err = ck.Create()
		if err != nil {
			lognew.Error(c, "OrderTradeBackInsert", lognew.Fields{"ck": ck, "err": err.Error()})
		}
		// 订单支付成功状态流转
		var trade models.OrderTrade
		tradeInfo, err := trade.GetByNO(ck.OutTradeNo)
		if err != nil {
			lognew.Error(c, "OrderTradeFind", lognew.Fields{"ck": ck, "err": err.Error()})
			c.XML(200, gin.H{
				"return_code": "FAIL",
				"return_msg":  "failed to verify sign, please retry!",
			})
			return
		}

		lognew.Info(c, "OrderBack-tradeInfo", lognew.Fields{"tradeInfo": tradeInfo})

		var order models.Order
		orderInfo, err := order.GetByID(tradeInfo.OrderId)
		if err != nil {
			lognew.Error(c, "orderFind", lognew.Fields{"ck": ck, "err": err.Error()})
			c.XML(200, gin.H{
				"return_code": "FAIL",
				"return_msg":  "failed to verify sign, please retry!",
			})
			return
		}

		lognew.Info(c, "OrderBack-orderInfo", lognew.Fields{"orderInfo": orderInfo})

		var neworder models.Order
		neworder.OrderId = orderInfo.OrderId
		neworder.PayNo = ck.TransactionId
		neworder.PayAccount = ck.Openid
		neworder.PayTradeNo = ck.OutTradeNo
		neworder.PayTime = time.Now().Format("2006-01-02 15:04:05")
		neworder.OrderStatus = constant.ORDER_STATUS_10
		_, err = neworder.Update(orderInfo.OrderId)

		if err != nil {
			lognew.Error(c, "orderUpdateError", lognew.Fields{"ck": ck, "err": err.Error()})
			c.XML(200, gin.H{
				"return_code": "FAIL",
				"return_msg":  "failed to verify sign, please retry!",
			})
			return
		}

		orderPay := models.OrderPay{
			OrderId:  orderInfo.OrderId,
			PayType:  "微信",
			PayPrice: float64(ck.TotalFee) / 100.0,
			PayDesc:  orderInfo.OrderName,
			PayCome:  1,
			PayNo:    ck.OutTradeNo,
			PayTime:  time.Now().Format("2006-01-02 15:04:05"),
		}
		_, _ = orderPay.Create() //微信支付 回调创建 pay记录

		//用户操作订单记录
		orlog := models.OrderOprateLog{
			OrderId:         orderInfo.OrderId,
			Title:           "订单支付成功",
			Desc:            "订单支付成功/操作人：微信服务器调用/支付金额：" + fmt.Sprintf("%0.2f", orderPay.PayPrice),
			LogType:         "3",
			OrderStatusName: "已支付/待排课",
			PayStatusName:   "已支付",
			LogName:         "订单支付成功",
			LogUid:          0,
		}
		_, _ = orlog.Create() // 订单支付成功

		lognew.Info(c, "OrderBack-SUCCESS", lognew.Fields{"backInfo": backInfo})

		go notice.NoticeByType(notice.OrderPaySuccess, orderInfo.OrderId, 0, 0) // 订单支付成功 消息通知
		go notice.NoticeByType(notice.OrderNeedCheck, orderInfo.OrderId, 0, 0)  // 订单支付成功 需要确认排课

		c.XML(200, gin.H{
			"return_code": "SUCCESS",
			"return_msg":  "OK",
		})
	} else {

		lognew.Info(c, "OrderBack-FAIL", lognew.Fields{"backInfo": backInfo})

		c.XML(200, gin.H{
			"return_code": "FAIL",
			"return_msg":  "failed to verify sign, please retry!",
		})
	}
	return
}
